﻿#region Copyright (c) 2000-2008 Developer Express Inc.
/*
{*******************************************************************}
{                                                                   }
{       Developer Express .NET Component Library                    }
{       AgDataGrid                                 }
{                                                                   }
{       Copyright (c) 2000-2008 Developer Express Inc.              }
{       ALL RIGHTS RESERVED                                         }
{                                                                   }
{   The entire contents of this file is protected by U.S. and       }
{   International Copyright Laws. Unauthorized reproduction,        }
{   reverse-engineering, and distribution of all or any portion of  }
{   the code contained in this file is strictly prohibited and may  }
{   result in severe civil and criminal penalties and will be       }
{   prosecuted to the maximum extent possible under the law.        }
{                                                                   }
{   RESTRICTIONS                                                    }
{                                                                   }
{   THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES           }
{   ARE CONFIDENTIAL AND PROPRIETARY TRADE                          }
{   SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS   }
{   LICENSED TO DISTRIBUTE THE PRODUCT AND ALL ACCOMPANYING .NET    }
{   CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY.                 }
{                                                                   }
{   THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED      }
{   FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE        }
{   COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE       }
{   AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT  }
{   AND PERMISSION FROM DEVELOPER EXPRESS INC.                      }
{                                                                   }
{   CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON       }
{   ADDITIONAL RESTRICTIONS.                                        }
{                                                                   }
{*******************************************************************}
*/
#endregion Copyright (c) 2000-2008 Developer Express Inc.

using System.Windows.Controls;
using System.Windows;
using DevExpress.AgDataGrid.Internal;
using System.Windows.Input;
using System.Windows.Shapes;
using System;
using System.Windows.Media;
using DevExpress.AgDataGrid.Data;
using System.Threading;
using System.Windows.Markup;
using System.Windows.Media.Animation;
namespace DevExpress.AgDataGrid {
	public enum AgDataGridColumnHeaderState { Normal, MouseOver, Pressed } 
	[TemplatePart(Name = AgDataGridColumnHeader.DATAGRID_ResizerName, Type = typeof(UIElement))]
	[TemplatePart(Name = AgDataGridColumnHeader.DATAGRID_DraggerName, Type = typeof(UIElement))]
	[TemplatePart(Name = AgDataGridColumnHeader.DATAGRID_RootElementName, Type = typeof(Panel))]
	[TemplatePart(Name = AgDataGridColumnHeader.DATAGRID_NormalAnimationName, Type = typeof(Storyboard))]
	[TemplatePart(Name = AgDataGridColumnHeader.DATAGRID_MouseOverAnimationName, Type = typeof(Storyboard))]
	[TemplatePart(Name = AgDataGridColumnHeader.DATAGRID_PressedAnimationName, Type = typeof(Storyboard))]
	[TemplatePart(Name = AgDataGridColumnHeader.DATAGRID_ThumbObjectTemplate, Type = typeof(DataTemplate))]
	[TemplatePart(Name = AgDataGridColumnHeader.DATAGRID_HeaderDraggingThumb, Type = typeof(UIElement))]
	public class AgDataGridColumnHeader : AgColumnCellBase, IDragableObject, IDropableObject {
		const string DATAGRID_RootElementName = "RootElement";
		const string DATAGRID_NormalAnimationName = "Normal";
		const string DATAGRID_MouseOverAnimationName = "MouseOver";
		const string DATAGRID_PressedAnimationName = "Pressed";
		const string DATAGRID_ResizerName = "Resizer";
		const string DATAGRID_DraggerName = "Dragger";
		const string DATAGRID_HeaderDraggingThumb = "HeaderDraggingThumb";
		const string DATAGRID_ThumbObjectTemplate = "ThumbObjectTemplate";
		UIElement resizer, dragger;
		ResizingController resizingController;
		DragController dragController;
		AgDataGridColumnHeaderState state;
		Panel rootElement;
		public static readonly DependencyProperty SortOrderProperty = DependencyProperty.Register("SortOrder",
				typeof(ColumnSortOrder), typeof(AgDataGridColumnHeader), new PropertyMetadata(OnSortOrderChanged));
		public static readonly DependencyProperty SortAscendentVisibilityProperty = DependencyProperty.Register("SortAscendentVisibility",
				typeof(Visibility), typeof(AgDataGridColumnHeader), null);
		public static readonly DependencyProperty SortDescendentVisibilityProperty = DependencyProperty.Register("SortDescendentVisibility",
				typeof(Visibility), typeof(AgDataGridColumnHeader), null);
		public AgDataGridColumnHeader(AgDataGridColumn column) : base(column) {
			DefaultStyleKey = typeof(AgDataGridColumnHeader);
			this.MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(ColumnHeader_MouseLeftButtonDown);
			this.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(ColumnHeader_MouseLeftButtonUp);
			this.MouseMove += new System.Windows.Input.MouseEventHandler(ColumnHeader_MouseMove);
			this.MouseLeave += new MouseEventHandler(ColumnHeader_MouseLeave);
			this.MouseEnter += new MouseEventHandler(ColumnHeader_MouseEnter);
			this.Loaded += new RoutedEventHandler(OnLoaded);
			SortOrder = Column.SortOrder;
			OnSortOrderChanged();
		}		
		static void OnSortOrderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
			AgDataGridColumnHeader header = d as AgDataGridColumnHeader;
			if(header == null) return;
			header.OnSortOrderChanged();
		}
		public virtual bool IsGroupedHeader { get { return false; } }
		protected bool IsDragableObject { get; set; }
		public void UpdateAllowResizing() {
			if(Resizer != null) Resizer.SetVisible(Column.CanUserResizing);
		}
		protected virtual void OnSortOrderChanged() {
			SortAscendentVisibility = SortOrder == ColumnSortOrder.Ascending ? Visibility.Visible : Visibility.Collapsed;
			SortDescendentVisibility = SortOrder == ColumnSortOrder.Descending ? Visibility.Visible : Visibility.Collapsed;
		}
		protected override double ColumnWidth { get { return Owner.GetColumnHeaderWidth(Column); }
		}
		public Visibility SortAscendentVisibility {
			get { return (Visibility)GetValue(SortAscendentVisibilityProperty); }
			private set { SetValue(SortAscendentVisibilityProperty, value); }
		}
		public Visibility SortDescendentVisibility {
			get { return (Visibility)GetValue(SortDescendentVisibilityProperty); }
			private set { SetValue(SortDescendentVisibilityProperty, value); }
		}
		public ColumnSortOrder SortOrder {
			get { return (ColumnSortOrder)GetValue(AgDataGridColumnHeader.SortOrderProperty); } 
			set { SetValue(AgDataGridColumnHeader.SortOrderProperty, value); } 
		}
		protected internal IAgDataGridColumnOwner Owner { get { return Column.Owner; } }
		protected IScrollOnDragging ScrollOnDragging { get { return Owner as IScrollOnDragging; } }
		protected internal int GroupIndex { get { return Column.GroupIndex; } set { Column.GroupIndex = value; } }
		protected int VisibleIndex { get { return Column.VisibleIndex; } set { Column.VisibleIndex = value; } }
		protected Panel RootElement { get { return rootElement; } }
		protected virtual internal UIElement Resizer { get { return resizer; } }
		protected UIElement Dragger { get { return dragger; } }
		protected ResizingController ResizingController { get { return resizingController; } }
		protected DragController DragController { get { return dragController; } }
		public bool IsDragging { get { return DragController != null; } } 
		public AgDataGridColumnHeaderState State {
			get { return state; }
			set {
				if(State == value) return;
				OnStateChanging();
				state = value;
				OnStateChanged();
			}
		}
		protected Style StateStyle { get { return Owner.GetColumnHeaderStyle(State); } }
		protected string StateName {
			get {
				switch(State) {
					case AgDataGridColumnHeaderState.Normal: return DATAGRID_NormalAnimationName;
					case AgDataGridColumnHeaderState.MouseOver: return DATAGRID_MouseOverAnimationName;
					case AgDataGridColumnHeaderState.Pressed: return DATAGRID_PressedAnimationName;
				}
				return "";
			}
		}
		protected virtual void OnStateChanging() {
		}
		protected virtual void OnStateChanged() {
			StyleLoader.ApplyStyle(this, StateStyle);
			VisualStateManager.GoToState(this, StateName, true);
		}		
		public override void OnApplyTemplate() {
			base.OnApplyTemplate();
			this.resizer = GetTemplateChild(DATAGRID_ResizerName) as UIElement;
			this.dragger = GetTemplateChild(DATAGRID_DraggerName) as UIElement;
			this.rootElement = GetTemplateChild(DATAGRID_RootElementName) as Panel;
			UpdateAllowResizing();
			if(!IsDragableObject)
				ToolTipService.SetToolTip(this, Column.HeaderToolTip);
		}
		void ColumnHeader_MouseMove(object sender, System.Windows.Input.MouseEventArgs e) {
			if(ResizingController != null) {
				ResizingController.MouseMove(e.GetPosition(this).X);
			}
			if(DragController != null) {
				DragController.Move(e.GetPosition(GetSurface()));
			}
		}
		bool CanSortOnMouseLeftButtonUp { get { return (ResizingController == null) && (DragController == null || !DragController.IsDragging); } }
		void ColumnHeader_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) {
			if(e.Handled) return;
			if(CanSortOnMouseLeftButtonUp) {
				Column.ChangeSortOnClick(KeyboardHelper.ShiftKey, KeyboardHelper.CtrlKey);
			}
			StopResizing();
			StopDrag();
			if(State != AgDataGridColumnHeaderState.Normal)
				State = AgDataGridColumnHeaderState.MouseOver;
		}
		void ColumnHeader_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e) {
			if(e.Handled) return;
			if(e.OriginalSource == Resizer) {
				StartResizing(e.GetPosition(this));
				return;
			}
			State = AgDataGridColumnHeaderState.Pressed;
			if(e.OriginalSource == Dragger) {
				StartDragging(e.GetPosition(this));
			}			
		}
		void ColumnHeader_MouseEnter(object sender, MouseEventArgs e) {
			State = AgDataGridColumnHeaderState.MouseOver;			
		}
		void ColumnHeader_MouseLeave(object sender, MouseEventArgs e) {
			State = AgDataGridColumnHeaderState.Normal;
		}
		protected virtual void OnLoaded(object sender, RoutedEventArgs e) {
			OnStateChanged();
		}
		Cursor cursorBeforeResizing = Cursors.Arrow;
		protected virtual void StartResizing(Point pt) {
			this.resizingController = new ResizingController(Column, pt.X);
			this.cursorBeforeResizing = Cursor;
			Cursor = Cursors.SizeWE;
			CaptureMouse();
		}
		protected virtual void StopResizing() {
			if(ResizingController == null) return;
			Cursor = cursorBeforeResizing;
			this.resizingController = null;
			ReleaseMouseCapture();
		}
		protected virtual void StartDragging(Point point) {
			if(!Column.CanUserMoving) return;
			this.dragController = new DragController(this, GetSurface(), point, new Point(Margin.Left,Margin.Top));
			DragController.StartDragShift = AgDataGrid.DefaultStartDragShift;
			DragController.ScrollOnDragging = ScrollOnDragging;
			CaptureMouse();
		}
		protected internal virtual Canvas GetSurface() { return ((AgDataGrid)Owner).Surface; }		
		protected virtual void StopDrag() {
			if(DragController == null) return;
			DragController.StopDrag();
			this.dragController = null;
			ReleaseMouseCapture();
		}
		protected virtual FrameworkElement GetDragShapeCore() {
			AgDataGridColumnHeader drag = new AgDataGridColumnHeader(Column);
			drag.Content = Content;
			drag.Opacity = .85;
			drag.Width = Width;
			drag.Height = Height;
			drag.IsDragableObject = true;
			return drag;
		}
		protected virtual FrameworkElement ThumbObject { get { return Owner.DragArrows;	} }
		#region IDragableObject Members
		FrameworkElement IDragableObject.CreateDragShape() { return GetDragShapeCore(); }	
		#endregion
		#region IDropableObject Members
		bool IDropableObject.CanAccept() { return true; } 
		bool IDropableObject.CanAccept(IDragableObject dragObject, Point position) {
			AgDataGridColumnHeader dragHeader = GetAcceptableDragHeader(dragObject);
			return dragHeader != null ? CanAcceptDragHeader(dragHeader, position) : false;
		}
		Rect IDropableObject.GetThumbRect(Point position) {
			return GetThumbRect(position);
		}
		void IDropableObject.AcceptDrag(IDragableObject dragObject, Point position) {
			AgDataGridColumnHeader dragHeader = dragObject as AgDataGridColumnHeader;
			if(dragHeader == null) return;
			double x = GetThumbLeft(2, position.X);
			SetAcceptDragObjectNewIndex(dragHeader, GetAcceptDragObjectNewIndex(dragHeader, x));
		}
		FrameworkElement IDropableObject.GetThumbObject() {
			return ThumbObject;
		}
		protected AgDataGridColumnHeader GetAcceptableDragHeader(IDragableObject dragObject) {
			AgDataGridColumnHeader dragHeader = dragObject as AgDataGridColumnHeader;
			if(dragHeader == null || dragHeader == this || dragHeader.Owner != Owner) return null;
			return dragHeader;
		}
		protected virtual bool CanAcceptDragHeader(AgDataGridColumnHeader dragHeader, Point position) {
			if(dragHeader.IsGroupedHeader && !dragHeader.Column.CanUserGroup) return false;
			double thumbLeft = GetThumbLeft(Column.VisibleIndex - dragHeader.Column.VisibleIndex, position.X);
			if(dragHeader.IsGroupedHeader && !IsGroupedHeader && thumbLeft < 0) thumbLeft = GetThumbLeftNoLimits(position.X); 
			if(thumbLeft < 0) return false;
			Rect slot = System.Windows.Controls.Primitives.LayoutInformation.GetLayoutSlot(this);
			double thumbPosition = slot.Left + thumbLeft;
			return Owner.IsInsideHeaderPanel(thumbLeft);
		}
		protected virtual double GetThumbLeftNoLimits(double positionX) {
			return positionX < GetWidth() / 2 ? 0 : GetWidth();
		}
		protected virtual double GetThumbLeft(int visibleIndexDiff, double positionX) {
			if(Math.Abs(visibleIndexDiff) == 1) {
				if(positionX < GetWidth() / 2) {
					return visibleIndexDiff < 0 ? 0 : -1;
				} else {
					return visibleIndexDiff > 0 ? GetWidth() : -1;
				}
			}
			return GetThumbLeftNoLimits(positionX);
		}
		protected virtual Rect GetThumbRect(Point position) {
			double x = GetThumbLeft(2, position.X);
			return new Rect(x, 0, 0, ActualHeight);
		}
		protected double GetWidth() {
			return ActualWidth == 0 ? Width : ActualWidth;
		}
		protected virtual int GetAcceptDragObjectNewIndex(AgDataGridColumnHeader dragHeader, double x) {
			if(dragHeader.VisibleIndex < VisibleIndex) {
				return x == 0 ? VisibleIndex - 1 : VisibleIndex;
			} 
			return x == 0 ? VisibleIndex : VisibleIndex + 1;
		}
		protected virtual void SetAcceptDragObjectNewIndex(AgDataGridColumnHeader dragHeader, int newIndex) {
			Owner.Ungroup(dragHeader.Column, newIndex);
		}
		#endregion
	}
	public class AgDataGridColumnGroupedHeader : AgDataGridColumnHeader {
		public AgDataGridColumnGroupedHeader(AgDataGridColumn column) : base(column) {
			DefaultStyleKey = typeof(AgDataGridColumnGroupedHeader);
		}
		public override bool IsGroupedHeader { get { return true; } }
		protected override bool CanAcceptDragHeader(AgDataGridColumnHeader dragHeader, Point position) {
			if(!dragHeader.Column.CanUserGroup) return false;
			if(dragHeader.GroupIndex < 0) return true;
			return GetThumbLeft(Column.GroupIndex - dragHeader.Column.GroupIndex, position.X) >= 0;
		}
		protected override int GetAcceptDragObjectNewIndex(AgDataGridColumnHeader dragHeader, double x) {
			return x == 0 ? GroupIndex : GroupIndex + 1;
		}		
		protected override void SetAcceptDragObjectNewIndex(AgDataGridColumnHeader dragHeader, int newIndex) {
			dragHeader.GroupIndex = newIndex;
		}
		protected override double ColumnWidth { get { return 0; } }
		protected override FrameworkElement GetDragShapeCore() {
			AgDataGridColumnGroupedHeader drag = new AgDataGridColumnGroupedHeader(Column);
			drag.Content = Content;
			drag.Opacity = .85;
			drag.Width = Width;
			drag.Height = Height;
			return drag;
		}
		protected override Size MeasureOverride(Size availableSize) {
			Size result = base.MeasureOverride(availableSize);
			result = new Size(Math.Ceiling(result.Width), Math.Ceiling(result.Height));
			return result;
		}
 	}
}
